package com.ysj.aipicturebe.config.MqConfig;

import cn.hutool.core.lang.Pair;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.ysj.aipicturebe.mapper.PictureMapper;
import com.ysj.aipicturebe.model.entity.Thumb;
import com.ysj.aipicturebe.model.msg.ThumbEvent;
import com.ysj.aipicturebe.service.ThumbService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor // 自动为 final 字段生成构造函数，便于依赖注入
public class listener {
    private final PictureMapper pictureMapper; // 图片数据访问对象
    private final ThumbService thumbService;   // 点赞服务

    /**
     *
     * 监听 RabbitMQ 消息队列，批量处理点赞事件
     * 在这种情况下，Spring 会自动把多个消息一次性打包成一个 List<消息体> 参数传给你。
     * @param messagePOList
     */
    @RabbitListener(queues = RabbitMQConfig.THUMB_QUEUE, containerFactory = "consumerBatchContainerFactory") // 监听指定队列，批量消费消息
    public void listenerMessage(List<String> messagePOList) {
        // 将消息字符串列表反序列化为 ThumbEvent 对象列表
        List<ThumbEvent> thumbEvents = messagePOList.stream()
                .map(item -> JSONUtil.toBean(item, ThumbEvent.class))
                .collect(Collectors.toList());

        // 点赞数变化统计，key 为 pictureId，value 为增减数量
        Map<Long, Long> countMap = new ConcurrentHashMap<>();
        // 需要插入的 Thumb 实体列表
        List<Thumb> thumbs = new ArrayList<>();

        // 构造查询条件，用于批量删除
        LambdaQueryWrapper<Thumb> wrapper = new LambdaQueryWrapper<>();
        // 标记是否需要删除
        AtomicReference<Boolean> needRemove = new AtomicReference<>(false);

        // 按 (userId, pictureId) 分组，获取每组的最新事件（偶数次操作视为抵消，返回 null）
        /**
         * 将每个用户对同一图片的所有操作归为一组；
         *
         * 如果这组的数量是偶数，说明是点赞+取消点赞配对，视为抵消，返回 null；
         *
         * 如果是奇数次，取最新一次（即最后一条）为最终的点赞状态（INCR 或 DECR）。
         */
        // 将点赞事件按用户ID和图片ID进行分组，并为每组提取出最终的点赞状态
        Map<Pair<Long, Long>, ThumbEvent> latestEvents = thumbEvents.stream()
                .collect(Collectors.groupingBy(
                        // 使用 Pair 作为分组键，包含 userId 和 pictureId
                        e -> Pair.of(e.getUserId(), e.getPictureId()),
                        // 对每组内的事件列表进一步处理
                        Collectors.collectingAndThen(
                                // 收集每组的所有事件为一个列表
                                Collectors.toList(),
                                list -> {
                                    // 按照事件发生时间升序排序，确保最早的在前
                                    list.sort(Comparator.comparing(ThumbEvent::getEventTime));
                                    // 如果该组事件数量为偶数，则表示点赞与取消点赞相互抵消，不产生实际操作
                                    if (list.size() % 2 == 0) {
                                        return null; // 返回 null 表示无需处理
                                    }
                                    // 若为奇数次操作，则取最后一次（最新的）事件作为最终状态
                                    return list.get(list.size() - 1);
                                }
                        )
                ));

        // 遍历每组的最新事件，处理点赞/取消点赞逻辑
        latestEvents.forEach((userBlogPair, event) -> {
            if (event == null) {
                return; // 偶数次操作已抵消，跳过
            }
            ThumbEvent.EventType finalAction = event.getType();
            //奇数次操作，获取最终的点赞状态
            if (finalAction == ThumbEvent.EventType.INCR) {
                // 点赞操作，计数加一
                countMap.merge(event.getPictureId(), 1L, Long::sum);
                /**相当于
                 * if (countMap.containsKey(event.getPictureId())) {
                 *     countMap.put(event.getPictureId(), countMap.get(event.getPictureId()) + 1L);
                 * } else {
                 *     countMap.put(event.getPictureId(), 1L);
                 * }
                 */
                // 构造 Thumb 实体，后续批量插入
                Thumb thumb = new Thumb();
                thumb.setPictureId(event.getPictureId());
                thumb.setUserId(event.getUserId());
                thumbs.add(thumb);
            } else {
                // 取消点赞，标记需要删除
                needRemove.set(true);
                // 构造删除条件
                wrapper.or()
                        .eq(Thumb::getUserId, event.getUserId())
                        .eq(Thumb::getPictureId, event.getPictureId());
                // 点赞数减一
                countMap.merge(event.getPictureId(), -1L, Long::sum);
            }
        });

        // 批量删除取消点赞的记录
        if (needRemove.get()) {
            thumbService.remove(wrapper);
        }
        // 批量更新图片的点赞数
        batchUpdateBlogs(countMap);
        // 批量插入新的点赞记录
        batchInsertThumbs(thumbs);
    }

    // 批量更新图片点赞数
    public void batchUpdateBlogs(Map<Long, Long> countMap) {
        if (!countMap.isEmpty()) {
            pictureMapper.batchUpdateThumbCount(countMap);
        }
    }

    // 批量插入点赞记录，分批处理
    public void batchInsertThumbs(List<Thumb> thumbs) {
        if (!thumbs.isEmpty()) {
            thumbService.saveBatch(thumbs, 500);
        }
    }
}